package com.eugene.workflow;

import java.util.List;

import com.eugene.element.FnCalendar;
import com.eugene.element.FnMeasure;
import com.eugene.element.Holiday;
import com.eugene.entity.CashFlow;
import com.eugene.quant.distribution.CumulativeNormalDistribution;

public class OptionNew extends FnProductNew{
//	private String optionType;
	private boolean call;
	private double strikePrice;
	private double contractSize;
	private double volatility;
	private FnProductNew underlying;
	
	private double dividendAmount;
	private double dividendYield;   
	
//	*************non-persistency member***************
	private FnCalendar settleDate;
	private double timeFactor;
	
//*********************End of Member*********************8	
	public OptionNew(){
		
	}
	
	
	public boolean isCall() {
		return call;
	}
	public void setCall(boolean call) {
		this.call = call;
	}
	public double getStrikePrice() {
		return strikePrice;
	}
	public void setStrikePrice(double strikePrice) {
		this.strikePrice = strikePrice;
	}
	public double getContractSize() {
		return contractSize;
	}
	public void setContractSize(double contractSize) {
		this.contractSize = contractSize;
	}
	public double getVolatility() {
		return volatility;
	}
	public void setVolatility(double volatility) {
		this.volatility = volatility;
	}
	public FnProductNew getUnderlying() {
		return underlying;
	}
	public void setUnderlying(FnProductNew underlying) {
		this.underlying = underlying;
	}
	
	public double getDividendAmount() {
		return dividendAmount;
	}
	public void setDividendAmount(double dividendAmount) {
		this.dividendAmount = dividendAmount;
	}
	public double getDividendYield() {
		return dividendYield;
	}
	public void setDividendYield(double dividendYield) {
		this.dividendYield = dividendYield;
	}
	public FnCalendar getSettleDate() {
		if(settleDate ==null){
			Holiday hol = getHolidayCalendar();
			settleDate = getBizDayRule().getBizDay(hol, getMaturityDate(), getBizDayNum());
		}
		return settleDate;
	}
	public void setSettleDate(FnCalendar settleDate) {
		this.settleDate = settleDate;
	}
	public double getTimeFactor() {
		return timeFactor;
	}
	public void setTimeFactor(double timeFactor) {
		this.timeFactor = timeFactor;
	}
//***********************End of getter and setter*******************

	@Override
	public FnMeasure calculateFnMeasure(FnCalendar baseDate){
		return null;
	}

	@Override
	public List<CashFlow> getCashFlows(FnCalendar baseDate){
		return null;
	}
	
	public double getPresentValue(FnCalendar baseDate){
		double rst;
		double underValue = this.getUnderlying().getFnMeasure(baseDate).getPrice()-getDividendAmount();
		double timeFactor = getDiscountCurve().getDaycountMethod().getTimeFactor(baseDate, getSettleDate());
		double dividendFactor =  Math.exp(-getDividendYield() * timeFactor);
		double df = getDiscountFactor(baseDate, getSettleDate());
		
		if(isCall()){
			rst = underValue* dividendFactor * getCdf(getD1(baseDate)) - getStrikePrice() * df* getCdf(getD2(baseDate));
		}
		rst = getStrikePrice() * df* getCdf(-getD2(baseDate))- underValue * dividendFactor* getCdf(-getD1(baseDate));
		return rst;
		
	}
	
	
	private double getCdf(double x){
		CumulativeNormalDistribution cdf = new CumulativeNormalDistribution();
		return cdf.primeOp(x);
	}
	
	private double getD1(FnCalendar baseDate){
		double underValue = this.getUnderlying().getFnMeasure(baseDate).getPrice()-getDividendAmount();
		double logRatio = Math.log(underValue /getStrikePrice() );
		
		double rate = getDiscountRate(baseDate, getSettleDate()).getIntRateValue();
		double timeFactor = getDiscountCurve().getDaycountMethod().getTimeFactor(baseDate, getSettleDate());
		double vol = getVolatility();
		double d1 =logRatio + ( rate + vol * vol / 2 ) * timeFactor;
		d1 = ( d1 - getDividendYield() * timeFactor) /  ( vol* Math.sqrt(timeFactor));
		return d1;
	}
	
	private double getD2(FnCalendar baseDate){
		double timeFactor = getDiscountCurve().getDaycountMethod().getTimeFactor(baseDate, getSettleDate());
		return getD1(baseDate)- getVolatility() * Math.sqrt(timeFactor);
	}
	
}
